﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Utils;
using System.Net;
using System.Web.Script.Serialization;
using log4net;
using System.Web;

namespace FbScraper
{
	public class Result
	{
		public payload payload { get; set; }
		public int error { get; set; }
	}

	public class payload
	{
		//public user_info user_info { get; set; }
		public int count { get; set; }
		public Dictionary<string, user> user_info { get; set; }

	}

	public class user
	{
		public long id { get; set; }
		public string title { get; set; }
		public string pic { get; set; }

	}

	public class PageScraper
	{
		ILog logger = LogManager.GetLogger("PageScraper");

		public int CollectedFanNum { get; set; }
		int? _fansNum;
		public int TotalFansNum //the total number of page fans as reported by the ajax call
		{
			get 
			{
				if(_fansNum.HasValue)
					return _fansNum.Value;
				return 0;
			}
			set
			{
				_fansNum = value;
			}
		}
		private void SetTotalFansNum(int num)
		{
			TotalFansNum = num;
		}

		public Dictionary<long, user> GetPageFans(long fanPageID, string fanPageURL, CookieContainer loginCookies)
		{
            
			// browsing to fan page
			if(logger.IsDebugEnabled)
				logger.DebugFormat("Starting to get fans for page");
			var resText = WebReq.GetWebResponse(fanPageURL + "?v=wall", 300000, false, loginCookies, null, null);
            TotalFansNum = GetFansNum(resText);
			// this cannot be changed facebook sends 100 even if you request more
			int numOfResults = 100;
			// these values are needed for the next calls. i do not know what there meaning is.
			var formID = new Regex("(?<=name=\"post_form_id\" value=\")[^\"]*").Match(resText).Value;
			var fb_dtsg = new Regex("(?<=name=\"fb_dtsg\" value=\")[^\"]*").Match(resText).Value;

			// regex to catch all idies
			Regex reg = new Regex("(?<=\"id\":)[^,]*");
			
			int counter = 0;
			// paging through to get all fans
			var pageNum = 0;
			Dictionary<long, user> supporters = new Dictionary<long, user>();
		
			int supportersUntilNow = 0;//this is in order to check if in the next round we have more results or the whole page didnt bring new ones.
			do
			{
				if (logger.IsDebugEnabled)
					logger.DebugFormat("Getting fans from page {0}", pageNum);
				// this is the actual call that returns a json with the user data
				var postData = string.Format("edge_type=fan&page={4}&limit={3}&node_id={0}&class=FanManager&post_form_id={1}&fb_dtsg={2}&post_form_id_source=AsyncRequest",
						fanPageID, formID, fb_dtsg, numOfResults, pageNum);
				try
				{
					resText = WebReq.GetWebResponse("http://www.facebook.com/ajax/social_graph/fetch.php?__a=1", 300000, false, loginCookies, null, postData);

				}
				catch (Exception ex)
				{
					logger.Error("error has occured", ex);
				}

				//IMPORTANT: if there are no more fans- return.
				var matches = reg.Matches(resText);
				if (matches.Count == 0)
					break;

				resText = resText.Substring(resText.IndexOf('{'));
				JavaScriptSerializer sd = new JavaScriptSerializer();
				Result result = sd.Deserialize<Result>(resText);
                if (result.payload.count == 0)
                    break;
				
				if (result == null || result.payload == null || result.payload.user_info == null)
					break;

				foreach (var userItem in result.payload.user_info)
				{
					try
					{
						supporters.Add(userItem.Value.id, userItem.Value);
					}
					catch (Exception ex)
					{
						logger.Error("The supporter id " + userItem.Value.id + " already exists", ex);
						//sometimes it brings the same supporter twice.
					}
				}

				//if in the current itteration no new user were added - it means we probably won't get any new users. break the loop.
				if (supportersUntilNow == supporters.Count)
					break;
				//keep the number of users collected up to now
				supportersUntilNow = supporters.Count;

				// move on to next page
				counter += matches.Count;
				pageNum++;
			}
			while (counter < TotalFansNum);
			// if the last page did not have 100 users on it then it is the last page.
			//while (Idies.Count % numOfResults == 0);
			CollectedFanNum = supporters.Count;
			return supporters;
		}

		public int GetFansNum(long fanPageID, string fanPageURL, CookieContainer loginCookies)
		{
            var resText = WebReq.GetWebResponse(fanPageURL + "?v=wall", 300000, false, loginCookies, null, null);
            var count = new Regex("(?<=uiNumberGiant[^>]*>)[\\d,]*").Match(resText).Value.Replace(",","");
            return Convert.ToInt32(count);
		}

        public int GetFansNum(String resText)
        {
            var count = new Regex("(?<=uiNumberGiant[^>]*>)[\\d,]*").Match(resText).Value.Replace(",", "");
            return Convert.ToInt32(count);
        }
	

	}

	public class ScraperUtils
	{
		static ILog logger = LogManager.GetLogger("ScrapeUtils");
		public static void Login(CookieContainer cookies, string username, string password)
		{
			try
			{
				var res = WebReq.GetWebResponse("http://facebook.com", 300000, false, cookies, null, null);
				// logging in
                var lsd = new Regex("(?<=name=\"lsd\" value=\")[^\"]*").Match(res).Value;
                string postData = "charset_test=%E2%82%AC%2C%C2%B4%2C%E2%82%AC%2C%C2%B4%2C%E6%B0%B4%2C%D0%94%2C%D0%84&return_session=0&legacy_return=1&display=&session_key_only=0&trynum=2&charset_test=%E2%82%AC%2C%C2%B4%2C%E2%82%AC%2C%C2%B4%2C%E6%B0%B4%2C%D0%94%2C%D0%84&persistent=1&default_persistent=1&login=Log+in" +
                    string.Format("&email={0}&pass={1}&lsd={2}&lsd={2}", HttpUtility.UrlEncode(username), HttpUtility.UrlEncode(password), lsd);
				var webRes = WebReq.GetHttpWebResponse("https://login.facebook.com/login.php?login_attempt=1", 300000, false, cookies, null, postData);
			}
			catch (Exception ex)
			{
				logger.Error("error during login", ex);
			}


		}
	}
}
